﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Habi.Solver.Common
{
    public class Win32API
    {
        internal struct Keyboard_LL_Hook_Data
        {
            public UInt32 vkCode;
            public UInt32 scanCode;
            public UInt32 flags;
            public UInt32 time;
            public IntPtr extraInfo;
        }

        internal struct Mouse_LL_Hook_Data
        {
            internal long yx;
            internal readonly int mouseData;
            internal readonly uint flags;
            internal readonly uint time;
            internal readonly IntPtr dwExtraInfo;
        }

        private static IntPtr pKeyboardHook = IntPtr.Zero;
        private static IntPtr pMouseHook = IntPtr.Zero;
        //钩子委托声明
        public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
        private static HookProc keyboardHookProc;
        private static HookProc mouseHookProc;

        //安装钩子
        [DllImport("user32.dll")]
        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr pInstance, int threadID);
        //卸载钩子
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
        [DllImport("user32.dll")]
        public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); //parameter 'hhk' is ignored.

        private static int KeyboardHookCallback(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code < 0)
            {
                return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
            }

            Keyboard_LL_Hook_Data khd = (Keyboard_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Keyboard_LL_Hook_Data));

            System.Diagnostics.Debug.WriteLine($"key event:{wParam}, key code:{khd.vkCode}, event time:{khd.time}");

            return 0;
        }

        private static int MouseHookCallback(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code < 0)
            {
                return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
            }

            Mouse_LL_Hook_Data mhd = (Mouse_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Mouse_LL_Hook_Data));
            System.Diagnostics.Debug.WriteLine($"mouse event:{wParam}, ({mhd.yx & 0xffffffff},{mhd.yx >> 32})");

            return 0;
        }
        

        //安装钩子方法
        public static bool InsertKeyboardHook()
        {
            if (pKeyboardHook == IntPtr.Zero)//不存在钩子时
            {
                //创建钩子
                keyboardHookProc = KeyboardHookCallback;
                //13表示全局键盘事件。
                pKeyboardHook = SetWindowsHookEx(13, keyboardHookProc, (IntPtr)0, 0);

                if (pKeyboardHook == IntPtr.Zero)//如果安装钩子失败
                {
                    RemoveKeyboardHook(); return false;
                }
            }

            return true;
        }

        public static bool InsertMouseHook()
        {
            if (pMouseHook == IntPtr.Zero)
            {
                mouseHookProc = MouseHookCallback;
                //14表示全局鼠标事件
                pMouseHook = SetWindowsHookEx(14, mouseHookProc, (IntPtr)0, 0);

                if (pMouseHook == IntPtr.Zero)
                {
                    RemoveMouseHook(); return false;
                }
            }

            return true;
        }
        
        public static bool RemoveKeyboardHook()
        {
            if (pKeyboardHook != IntPtr.Zero)
            {
                if (UnhookWindowsHookEx(pKeyboardHook))
                {
                    pKeyboardHook = IntPtr.Zero;
                }
                else
                {
                    return false;
                }
            }

            return true;
        }

        public static bool RemoveMouseHook()
        {
            if (pMouseHook != IntPtr.Zero)
            {
                if (UnhookWindowsHookEx(pMouseHook))
                {
                    pMouseHook = IntPtr.Zero;
                }
                else
                {
                    return false;
                }
            }

            return true;
        }
    }

}
